package fr.teuteuf.runstickmanrun.map;

import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;

import fr.teuteuf.runstickmanrun.Constants;
import fr.teuteuf.runstickmanrun.IUpdatable;
import fr.teuteuf.runstickmanrun.map.block.AbstractMapBlock;
import fr.teuteuf.runstickmanrun.map.block.BasicBlock;
import fr.teuteuf.runstickmanrun.map.block.ObstructedPathsBlock;
import fr.teuteuf.runstickmanrun.map.block.PicksBlock;
import fr.teuteuf.runstickmanrun.map.block.SplitStairsBlock;
import fr.teuteuf.runstickmanrun.map.block.StairsAndPlatformsBlock;
import fr.teuteuf.runstickmanrun.map.block.StairsAndTowerBlock;
import fr.teuteuf.runstickmanrun.map.block.SuccessiveHolesBlock;
import fr.teuteuf.runstickmanrun.map.tile.Tile;
import fr.teuteuf.runstickmanrun.screen.AbstractGameScreen;

public class MapGenerator implements IUpdatable {
	
	private World world;
	private AbstractGameScreen gameScreen;
	private Array<Tile> tiles;
	private Array<IUpdatable> updatableTiles;
	private Array<AbstractMapBlock> mapBlocks;
	private Array<AbstractMapBlock> activeMapBlocks;
	private AbstractMapBlock basicBlock;
	private int nbHorizontalTiles;
	
	public MapGenerator(AbstractGameScreen abstractGameScreen, int difficultyLevel) {
		this.world = abstractGameScreen.getWorld();
		this.gameScreen = abstractGameScreen;
		
		basicBlock = new BasicBlock();
		
		mapBlocks = new Array<AbstractMapBlock>();
		mapBlocks.add(new SuccessiveHolesBlock(difficultyLevel));
		mapBlocks.add(new ObstructedPathsBlock(difficultyLevel));
		mapBlocks.add(new StairsAndTowerBlock(difficultyLevel));
		mapBlocks.add(new SplitStairsBlock(difficultyLevel));
		mapBlocks.add(new PicksBlock(difficultyLevel));
		mapBlocks.add(new StairsAndPlatformsBlock(difficultyLevel));
//		mapBlocks.add(new TestBlock());

		activeMapBlocks = new Array<AbstractMapBlock>();
		for(AbstractMapBlock mapBlock : mapBlocks) {
			if(mapBlock.getMinDifficultyLevel() <= difficultyLevel) {
				activeMapBlocks.add(mapBlock);
			}
		}
		
		tiles = new Array<Tile>();
		updatableTiles = new Array<IUpdatable>();
		nbHorizontalTiles = 0;

		nbHorizontalTiles += basicBlock.generateBlock(world, this, nbHorizontalTiles);
	}

	@Override
	public void update(float elapsedTime) {
		int playerPosition = (int) (gameScreen.getFirstPlayer().getPosition().x * Constants.BOX_TO_WORLD);
		while(nbHorizontalTiles * Tile.TILE_SIZE < playerPosition + Constants.WIDTH_RESOLUTION * Constants.SCREENS_AFTER_PLAYER) {
			addMapBlock();
		}
		
		for(IUpdatable updatableTile : updatableTiles) {
			updatableTile.update(elapsedTime);
		}
		
		while(tiles.get(0).getPosition().x < playerPosition - Constants.WIDTH_RESOLUTION * Constants.SCREENS_BEFORE_PLAYER) {
			tiles.get(0).destroy();
			if(tiles.get(0) instanceof IUpdatable) {
				updatableTiles.removeIndex(0);
			}
			tiles.removeIndex(0);
		}
	}
	
	private void addMapBlock() {
		if(activeMapBlocks.size > 0) {
			int indexBlock = MathUtils.random(activeMapBlocks.size - 1);
			nbHorizontalTiles = activeMapBlocks.get(indexBlock).generateBlock(world, this, nbHorizontalTiles);
		}
		nbHorizontalTiles = basicBlock.generateBlock(world, this, nbHorizontalTiles);
	}
	
	public void addTile(Tile t) {
		tiles.add(t);
		if(t instanceof IUpdatable) {
			updatableTiles.add((IUpdatable) t);
		}
	}
	
	public Array<Tile> getTiles() {
		return tiles;
	}
	
	public void changeCurrentDifficulty(int level) {
		activeMapBlocks.clear();
		for(AbstractMapBlock mapBlock : mapBlocks) {
			mapBlock.setCurrentLevel(level);
			if(mapBlock.getMinDifficultyLevel() <= level) {
				activeMapBlocks.add(mapBlock);
			}
		}
	}
}
